package jch.learn.java.basics.chapter14.blockingQueue;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

// 使用阻塞队列来控制一组线程。完成在一个目录及它的所有子目录下搜索所有文件，打印出包含指定关键字的行。
public class BlockingQueueTest {

    private static final int FILE_QUEUE_SIZE = 10;
    private static final int SEARCH_THREADS = 100;
    private static final File DUMMY = new File("");
    private static BlockingQueue<File> queue = new ArrayBlockingQueue<>(FILE_QUEUE_SIZE);

    public static void main(String[] args){
        try(Scanner in = new Scanner(System.in)){
            System.out.print("Enter base directory: ");
            String directory = in.nextLine();
            System.out.print("Enter keyword: ");
            String keyword = in.nextLine();
            // 生产者 线程
            Runnable enumerator = () -> {
                try{
                    enumerate(new File(directory));
                    queue.put(DUMMY);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            new Thread(enumerator).start();

            // 消费者 线程组
            for (int i = 0; i < SEARCH_THREADS; i++) {
                Runnable searcher = () -> {
                    try{
                        boolean done = false;
                        while(!done){
                            File file = queue.take();
                            if (file == DUMMY){
                                queue.put(file);
                                done = true;
                            }else {
                                search(file,keyword);
                            }
                        }
                    } catch (InterruptedException | FileNotFoundException e) {
                        e.printStackTrace();
                    }
                };
                new Thread(searcher).start();
            }
        }
    }

    // 枚举在目录下及子目录下的所有文件并将它们放入阻塞队列中。(若没有上限的话，将很快就包含所有找到的文件)
    public static void enumerate(File directory) throws InterruptedException {
        File[] files = directory.listFiles();
        for (File file:files) {
            if (file.isDirectory()){
                enumerate(file);
            }else {
                queue.put(file);
            }
        }
    }

    // 检索文件内容 找出包含指定关键字的行
    public static void search(File file,String keyword) throws FileNotFoundException {
        try(Scanner in = new Scanner(file,"UTF-8")){
            int lineNumber = 0;
            while(in.hasNextLine()){
                lineNumber ++;
                String line = in.nextLine();
                if (line.contains(keyword)){
                    System.out.printf("%s:%d:%s%n",file.getPath(),lineNumber,line);
                }
            }
        }
    }

}
